package tcp

/**
 * A echo server to test whether the server is functioning normally
 */

import (
	"context"
	"go.uber.org/zap"
	"io"
	"net"
	log "proxy/logger"
	"proxy/utils/atomic"
	"proxy/utils/wait"
	"sync"
	"time"
)

const (
	// RetryTime 断线重连时间
	RetryTime          = time.Second
	TcpKeepAlivePeriod = 30 * time.Second
)

// EchoHandler echos received line to client, using for test
type EchoHandler struct {
	activeConn sync.Map
	closing    atomic.Boolean
}

// MakeEchoHandler creates EchoHandler
func MakeEchoHandler() *EchoHandler {
	return &EchoHandler{}
}

// EchoClient is client for EchoHandler, using for test
type EchoClient struct {
	Conn    net.Conn
	Waiting wait.Wait
}

// Close close connection
func (c *EchoClient) Close() error {
	c.Waiting.WaitWithTimeout(10 * time.Second)
	c.Conn.Close()
	return nil
}

// Handle echos received line to client
func (h *EchoHandler) Handle(ctx context.Context, conn net.Conn) {
	if h.closing.Get() {
		// closing handler refuse new connection
		_ = conn.Close()
	}
	client := &EchoClient{
		Conn: conn,
	}
	h.activeConn.Store(client, struct{}{})
	srvConn, err := net.Dial("tcp", "192.168.3.66:2375")
	if err != nil {
		log.Error(ctx, "dial srcConn failed", zap.Error(err))
	}
	defer srvConn.Close()
	defer conn.Close()
	//srvConn.(*net.TCPConn).SetKeepAlive(true)
	//srvConn.(*net.TCPConn).SetKeepAlivePeriod(TcpKeepAlivePeriod)
	log.Info(nil, "client ip", zap.String("ip", conn.RemoteAddr().String()))
	go io.Copy(srvConn, conn)
	io.Copy(conn, srvConn)
}

// Close stops echo handler
func (h *EchoHandler) Close() error {
	log.Info(nil, "handler shutting down...")
	h.closing.Set(true)
	h.activeConn.Range(func(key interface{}, val interface{}) bool {
		client := key.(*EchoClient)
		_ = client.Close()
		return true
	})
	return nil
}
